iT邦幫忙

2021 iThome 鐵人賽

DAY 23
0

State Flow 是從 Shared Flow 繼承而來的,跟 Shared Flow 不同的地方在於它是有初始值的,至少會重播一個值給訂閱者,所以它最少會記得一個值。

這邊的值,就代表儲存的狀態 (State),所以我們如果要在多個訂閱者中發送狀態,我們就可以使用 State Flow。

既然是繼承 Shared flow,那麼它也是 Hot flow,也不會自己停下來。在 State 中有一個可以更新的 value ,這個值就是實際 State 的值。

class Day23 {
    private val _state = MutableStateFlow(false)
    val state = _state.asStateFlow()

    suspend fun updateResult(value: Boolean) {
        delay(200)
        _state.update { value }
    }
}

在這個類別中,我們一樣採用的是限制在這個類別裡更新,讓 MutableStateFlow 負責更新,對外只有讓外面的使用者使用 StateFlow ,而這邊的 StateFlow 我們是使用 MutableStateFlow 的 asStateFlow() 來將 MutableStateFlow 轉換成 StateFlow。
而另外我們建立一個函式 updateResult可以更新 MutableStateFlow 的值,其中更新 MutableStateFlow 值的方式是使用 update{}

update 函式的內容我們來看一下

public inline fun <T> MutableStateFlow<T>.update(function: (T) -> T) {
    while (true) {
        val prevValue = value
        val nextValue = function(prevValue)
        if (compareAndSet(prevValue, nextValue)) {
            return
        }
    }
}

在這個函式中我們注意到它會一直執行帶進來的 lambda,並將 lambda 的回傳值作為 nextValue ,當現在的值以及 nextValue 相同時,就會跳出這個無窮迴圈,否則將會一直在這個迴圈裡更新現在的值。

所以我們知道,當更新 StateFlow 的 value 時,如果 value 已經與現在的 value 一樣,那麼就不會再次寫入,也就是説,當現在的狀態與更新狀態一樣時,就不會有任何動作。

執行它看看:

fun main() = runBlocking {
    val day23 = Day23()
    val state1 = day23.state

    state1.collect {
        println("$it")
        day23.updateResult(true)
    }
    println("done")
}
false
true

→ 由結果我們可以得知,collect 會一直去監聽 StateFlow 的狀態值,當狀態有改變的時候,就會立即跑進 collect 這個 lambda 中,接著就會繼續等待,因為它是一個 Hot Flow。所以 "done" 在這個例子下就永遠都不會被呼叫了。

--請接續下篇--


由本系列文改編的《Kotlin 小宇宙:使用 Coroutine 優雅的執行非同步任務》已經上市囉。

有興趣的讀者歡迎參考:https://coroutine.kotlin.tips/
天瓏書局


上一篇
Day22:Hot Flow - SharedFlow (Part II)
下一篇
Day24:Hot flow - State Flow (part II)
系列文
Coroutine 停看聽30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言